﻿using System;
using System.Collections.Generic;
using System.Threading;
using System.Windows.Input;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;

namespace WholeSlideImageViewer
{
    internal class MainWindowViewModel : ViewModelBase
    {
        private readonly IMainWindowInteraction _interaction;
        private readonly IAddressService _addressService;
        private readonly IDeepZoomImageSource _deepZoomImageSource;
        private readonly IExportService _exportService;

        private readonly ILogger _logger;


        #region 页面状态

        private string? _id;
        private bool _isLoaded;
        private string? _url;

        public string? Id { get => _id; set => OnPropertyChanged(nameof(Id), ref _id, value); }
        public bool IsLoaded { get => _isLoaded; set => OnPropertyChanged(nameof(IsLoaded), ref _isLoaded, value); }
        public string? Url { get => _url; set => OnPropertyChanged(nameof(Url), ref _url, value); }

        #endregion

        #region 页面指令

        private ICommand? _fileOpenCommand;
        private ICommand? _fileExportTiffCommand;
        private ICommand? _fileExportOptiCommand;
        private ICommand? _fileTextPropertiesCommand;
        private ICommand? _fileAssociatedImagesCommand;
        private ICommand? _fileAboutCommand;
        private ICommand? _fileExitCommand;

        public ICommand FileOpenCommand => _fileOpenCommand ??= new RelayCommand(_ => FileOpen(), _ => true);
        public ICommand FileExportTiffCommand => _fileExportTiffCommand ??= new RelayCommand(_ => FileExportTiff(), _ => _isLoaded);
        public ICommand FileExportOptiCommand => _fileExportOptiCommand ??= new RelayCommand(_ => FileExportOpti(), _ => _isLoaded);
        public ICommand FileTextPropertiesCommand => _fileTextPropertiesCommand ??= new RelayCommand(_ => FileTextProperties(), _ => _isLoaded);
        public ICommand FileAssociatedImagesCommand => _fileAssociatedImagesCommand ??= new RelayCommand(_ => FileAssociatedImages(), _ => _isLoaded);
        public ICommand FileAboutCommand => _fileAboutCommand ??= new RelayCommand(_ => FileAbout(), _ => true);
        public ICommand FileExitCommand => _fileExitCommand ??= new RelayCommand(_ => FileExit(), _ => true);

        #endregion

        [Obsolete("Only use this constructor in design time.", true)]
        public MainWindowViewModel()
        {
            throw new NotSupportedException();
        }

        public MainWindowViewModel(IServiceProvider serviceProvider, IMainWindowInteraction interaction)
        {
            _interaction = interaction;
            _addressService = serviceProvider.GetService<IAddressService>();
            _deepZoomImageSource = serviceProvider.GetService<IDeepZoomImageSource>();
            _exportService = serviceProvider.GetService<IExportService>();

            _logger = serviceProvider.GetService<ILogger<MainWindowViewModel>>();
        }

        public async void FileOpen()
        {
            string? fileName = _interaction.ShowOpenFileDialog();
            if (fileName is null)
            {
                return;
            }

            bool result = _addressService.TryGetAccessAddress(out Uri? uri);
            if (!result)
            {
                _interaction.AlertServerLoadFailure();
                return;
            }

            string? id;
            try
            {
                id = await _deepZoomImageSource.OpenAsync(fileName);

            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "文件加载失败。");
                _interaction.AlertSlideLoadFailure(ex);
                return;
            }

            if (string.IsNullOrEmpty(id))
            {
                _logger.LogError("文件加载失败，但是没有抛出异常。");
                _interaction.AlertSlideLoadFailure(null);
                return;
            }

            Id = id;
            IsLoaded = true;
            Url = uri!.ToString() + "index.html?id=" + id;
            _logger.LogInformation("WebBrowser跳转：{0}", Url);
            _interaction.NavigateWebView(Url);
        }

        public async void FileExportTiff()
        {
            string? fileName = _interaction.ShowExportTiffFileDialog();
            if (fileName is null)
            {
                return;
            }

            ITiffOutputOptions? result = _interaction.ShowTiffExportOptions();
            if (result is null)
            {
                return;
            }

            string? id = _id;
            if (id is null)
            {
                return;
            }
            RetainableDeepZoomGenerator? image = _deepZoomImageSource.Retain(id);
            if (image is null)
            {
                return;
            }

            var cts = new CancellationTokenSource();
            try
            {
                IExportProgress progress = await _exportService.ExportTiffAsync(image, result, fileName, cts.Token);

                _interaction.ShowTiffExportDialog(progress, cts);
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "TIFF导出失败。");
                _interaction.AlertTiffExportFailure(ex);
            }
            finally
            {
                await image.DisposeAsync().ConfigureAwait(false);
            }
        }

        public async void FileExportOpti()
        {
            string? fileName = _interaction.ShowExportOptiFileDialog();
            if (fileName is null)
            {
                return;
            }

            IOptiOutputOptions? result = _interaction.ShowOptiExportOptions();
            if (result is null)
            {
                return;
            }

            string? id = _id;
            if (id is null)
            {
                return;
            }
            RetainableDeepZoomGenerator? image = _deepZoomImageSource.Retain(id);
            if (image is null)
            {
                return;
            }

            var cts = new CancellationTokenSource();
            try
            {
                IExportProgress progress = await _exportService.ExportOptiAsync(image, result, fileName, cts.Token);

                _interaction.ShowOptiExportDialog(progress, cts);
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "OPTI导出失败。");
                _interaction.AlertOptiExportFailure(ex);
            }
            finally
            {
                await image.DisposeAsync().ConfigureAwait(false);
            }
        }

        public async void FileTextProperties()
        {
            string? id = _id;
            if (id is null)
            {
                return;
            }
            IEnumerable<KeyValuePair<string, string>>? items = null;
            try
            {
                items = await _deepZoomImageSource.GetTextPropertiesAsync(id);
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "获取属性失败。");
                _interaction.AlertShowPropertiesFailure(ex);
                return;
            }
            if (items is null)
            {
                _logger.LogError("获取属性失败，但是没有抛出异常。");
                _interaction.AlertShowPropertiesFailure(null);
                return;
            }

            _interaction.ShowPropertiesDialog(items);
        }

        public async void FileAssociatedImages()
        {
            string? id = _id;
            if (id is null)
            {
                return;
            }
            IEnumerable<string>? items = null;
            try
            {
                items = await _deepZoomImageSource.GetAssociatedImageNamesAsync(id);
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "获取附加图片失败。");
                _interaction.AlertShowAssociatedImagesFailure(ex);
                return;
            }
            if (items is null)
            {
                _logger.LogError("获取附加图片失败，但是没有抛出异常。");
                _interaction.AlertShowAssociatedImagesFailure(null);
                return;
            }

            _interaction.ShowAssociatedImagesDialog(items);
        }

        public void FileAbout()
        {
            _interaction.AlertAbout();
        }

        public void FileExit()
        {
            _interaction.ApplicationExit();
        }
    }
}
